#pragma once
#include "exchange.hpp"
#include "message.hpp"
#include "queue.hpp"
#include "binding.hpp"
#include <iostream>
#include <string>
using namespace std;

namespace rbmq {
    class VirtualHost {
    public :
        typedef shared_ptr<VirtualHost> ptr;
        VirtualHost(const string& host_name, string& basedir, const string& dbfile) 
            :_host_name(host_name)
            ,_emp(make_shared<ExchangeManager>(dbfile))
            ,_mqmp(make_shared<MsgQueueManager>(dbfile))
            ,_bmp(make_shared<BindingManager>(dbfile))
            ,_msgp(make_shared<MessageManager>(basedir))
        {
            // 获取到所有的队列信息，通过队列名称恢复历史消息
            QueueMap msgmap = _mqmp->getAllQuues();
            // 初始化队列管理信息句柄，就会自动恢复
            for (auto& map : msgmap) {
                _msgp->initQueueMessage(map.first);
            }
        }

        // 交换机的声明
        void declareExchange(const string& name, mqNs::ExchangeType type, bool durable, bool auto_delete, const google::protobuf::Map<string, string>& args) {
            _emp->declareExchange(name, type, durable, auto_delete, args);
        }
        // 删除交换机
        bool deleteExchange(const string& exchange_name) {
            // 在删除交换机的同时，需要将交换机相关的绑定信息也同时删除
            // 首先要找到交换机
            rbmq::Exchange::ptr exp = _emp->selectExchange(exchange_name);
            if (exp.get() == nullptr) {
                LOG(Debug) << "删除交换机: " << exchange_name << " 失败: 没有找到对应的交换机" << endl;
                return false;
            }
            return _bmp->removeExchangeBindings(exchange_name, exp->_durable);
        }
        // ---------------------------------------------------------------------------------------------------------------------------

        // 队列的声明
        bool declareQueue(const string& queue_name, bool durable, bool exclusive, bool auto_delete, const google::protobuf::Map<string, string>& args) {
            // 初始化队列的消息管理句柄，进行消息的存储管理
            _msgp->initQueueMessage(queue_name);
            // 队列的创建
            return _mqmp->declareQueue(queue_name, durable, exclusive, auto_delete, args);
        }
        
        // 队列的删除
        void deleteQueue(const string& queue_name) {
            // 删除一个队列的时候，队列相关的信息有两个：队列的消息，队列的绑定信息
            MsgQueue::ptr queue = _mqmp->selectQueue(queue_name);
            if (queue.get() == nullptr) {
                LOG(Debug) << "删除队列: " << queue_name << " 失败: 没有找到该队列" << endl;
                return;
            }
            _msgp->destroyQueueMessage(queue_name);
            _bmp->removeMsQueueBindings(queue_name, queue->_durable);
            _mqmp->deleteQueue(queue_name);
        }
        // ---------------------------------------------------------------------------------------------------------------------------

        // 增加一个绑定
        bool Bind(const string& queue_name, const string& exchange_name, const string& binding_key) {
            // 交换机必须存在和队列必须存在才能绑定
            Exchange::ptr exp = _emp->selectExchange(exchange_name);
            // 所以先要判断这交换机和队列是否都存在
            if (exp.get() == nullptr) {
                LOG(Debug) << "增加绑定信息失败: 没有找到指定的交换机: " << exchange_name << endl;
                return false;
            }
            MsgQueue::ptr queue = _mqmp->selectQueue(queue_name);
            if (queue.get() == nullptr) {
                LOG(Debug) << "增加绑定信息失败: 没有找到指定的队列: " << queue_name << endl;
                return false;                
            }
            // 绑定信息是否需要持久化存储取决于队列和交换机是否需要持久化存储，只有队列和交换机都需要持久化存储，绑定信息才需要持久化存储
            return _bmp->bind(exchange_name, queue_name, binding_key, queue->_durable && exp->_durable);
        }

        // 解绑一个绑定信息
        void unBind(const string& queue_name, const string& exchange_name) {
            Exchange::ptr exp = _emp->selectExchange(exchange_name);
            // 所以先要判断这交换机和队列是否都存在
            if (exp.get() == nullptr) {
                LOG(Debug) << "解绑失败: 没有找到指定的交换机: " << exchange_name << endl;
                return;
            }
            MsgQueue::ptr queue = _mqmp->selectQueue(queue_name);
            if (queue.get() == nullptr) {
                LOG(Debug) << "解绑失败: 没有找到指定的队列: " << queue_name << endl;
                return;                
            }
            return _bmp->unbind(exchange_name, queue_name, exp->_durable && queue->_durable);
        }

        // 获取指定的交换机
        Exchange::ptr selectExchange(const string& exchange_name) {
            return _emp->selectExchange(exchange_name);
        }

        // 获取指定交换机的所有的绑定信息
        MsQueueBindingMap exchangeBindings(const string& exchange_name) {
            return _bmp->getExchangeBindings(exchange_name);
        }
        // ---------------------------------------------------------------------------------------------------------------------------

        // 发布一条消息
        bool basicPublish(const string& queue_name, mqNs::BasicProperties* bp, const string& body) {
            // 如果队列不存在，也就发布不了消息，所以先要确认队列存在
            MsgQueue::ptr queue = _mqmp->selectQueue(queue_name);
            if (queue.get() == nullptr) {
                LOG(Debug) << "发布消息失败: 没有找到指定队列: " << queue_name << endl;
                return false;
            }

            // 发布一条消息就是新建一条消息
            // 消息是否需要持久化也取决于队列是否需要持久化，如果队列都不需要持久化，那么消息持久化也就没有意义了
            if (_msgp.get() == nullptr) {
            }
            return _msgp->insert(queue_name, bp, body, queue->_durable);
            return true;

        }

        // 获取一条队首消息，进行发布
        MessagePtr basicConsume(const string& queue_name) {
            return _msgp->front(queue_name);
        }

        // 确认一条消息: 对指定队列里的制定一条消息进行确认
        void basicAck(const string& queue_name, const string& msg_id) {
            _msgp->ack(queue_name, msg_id);
        }


        // 判断一个交换机是否存在
        bool existsExchange(const string& exchange_name) {
            return _emp->exists(exchange_name);
        }

        // 判断一个队列是否存在
        bool existsQueue(const string& queue_name) {
            return _mqmp->exists(queue_name);
        }

        // 获取所有队列
        QueueMap getAllQueue() {
            return _mqmp->getAllQuues();
        }

        bool existsBinding(const string& exchange_name, const string& queue_name) {
            return _bmp->exists(exchange_name, queue_name);
        }

        void clear() {
            _emp->clear();
            _mqmp->clear();
            _bmp->clear();
            _msgp->clear();
        }
    private :
        string _host_name;
        ExchangeManager::ptr _emp; // 交换机数据管理句柄
        MsgQueueManager::ptr _mqmp; // 消息队列数据管理句柄
        BindingManager::ptr _bmp; // 绑定信息数据管理句柄
        MessageManager::ptr _msgp; // 消息数据管理句柄
    };
};
